package com.bbex.controller;

import com.bbex.config.AliYunAuthenticateSigConfig;
import com.bbex.config.UserConfig;
import com.bbex.config.sercurity.RedisSessionUser;
import com.bbex.constant.Constants;
import com.bbex.constant.SercurityConstant;
import com.bbex.disruptor.DisruptorData;
import com.bbex.disruptor.DisruptorManager;
import com.bbex.entity.PlatUser;
import com.bbex.entity.PlatUserOplog;
import com.bbex.entity.UserTagConfig;
import com.bbex.enums.*;
import com.bbex.exception.PlatException;
import com.bbex.google.GoogleAuthenticator;
import com.bbex.pojo.GlobalMessageResponseVo;
import com.bbex.pojo.ResponsePage;
import com.bbex.query.UserLoginLogQuery;
import com.bbex.reactive.data.mongo.domain.UserLoginLog;
import com.bbex.reactive.data.mongo.enums.SecurityLogEnums;
import com.bbex.service.UserLoginLogService;
import com.bbex.service.*;
import com.bbex.util.*;
import com.bbex.util.AliYunAuthenticateSigUtils;
import com.bbex.vo.*;
import com.bbex.valid.ValidateFiled;
import com.bbex.valid.ValidateGroup;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
//import reactor.core.scheduler.Schedulers;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/bbuni")
public class PlatUserController {

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    private static Logger logger = LoggerFactory.getLogger(PlatUserController.class);

    @Resource(name = "stringRedisTemplate")
    ValueOperations<String, String> valOpsStr;

    @Autowired
    private PlatUserService platUserService;
    @Autowired
    private MessageSendService messageSendService;
   /* @Autowired
    private BaiduApiService baiduApiService;
    @Autowired
    private CardRepository cardRepository;*/
    @Autowired
    private UserLoginLogService userLoginLogService;
    @Autowired
    private SmsMessageService smsMessageService;
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Value("${password.resetUrl}")
    private String resetUrl = "https://www.bbex.one/bbex/resetPassword";

    @Value("${register.switch}")
    private String registerSwitch = "1";

    @Autowired
    private UserConfig userConfig;

    @Autowired
    private AliYunAuthenticateSigConfig aliYunAuthenticateSigConfig;

    @Autowired
    private UserTagApplyService userTagApplyService ;

    /**
     * 密码前端加密后长度变了，不能使用正则
     *
     * @param platUserVO
     * @return
     */
    @ValidateGroup(fileds = {
            @ValidateFiled(index = 0, filedName = "registerType", isEnums = true, enums = "1,2", notNull = true, errMsg = "注册类型不正确"),
            @ValidateFiled(index = 0, filedName = "password", notNull = true, errMsg = "请输入格式正确的密码"),
            @ValidateFiled(index = 0, filedName = "mail", regStr = Constants.EMAIL_PATTERN, notNull = true, when = "{\"filedName\":\"registerType\",\"value\":\"2\"}", errMsg = "请输入正确的邮箱"),
            @ValidateFiled(index = 0, filedName = "mobile", notNull = true, when = "{\"filedName\":\"registerType\",\"value\":\"1\"}", errMsg = "请输入正确的手机号"),
            @ValidateFiled(index = 0, filedName = "code", notNull = false, errMsg = "验证码不正确"),
            @ValidateFiled(index = 0, filedName = "countryId", errMsg = "国籍不正确"/*, when = "{\"filedName\":\"registerType\",\"value\":\"1\"}"*/),
            @ValidateFiled(index = 0, filedName = "countryCode", errMsg = "区号不正确"/*, when = "{\"filedName\":\"registerType\",\"value\":\"1\"}"*/)
    })

    //用户注册
    @PostMapping("/user/register")
    public Mono<GlobalMessageResponseVo> register(PlatUserVO platUserVO) {
        /*ServerHttpResponse response = ctx.getResponse();
        HttpHeaders headers = response.getHeaders();
        headers.add("Access-Control-Allow-Origin", "*");
        headers.add("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        headers.add("Access-Control-Max-Age", "3600");
        headers.add("Access-Control-Allow-Headers", "*");
        headers.add("Access-Control-Expose-Headers", "*");
        headers.add("Access-Control-Allow-Credentials", "true");*/

        if ("0".equals(registerSwitch)) {
            return Mono.just(GlobalMessageResponseVo.newErrorInstance("暂停注册！"));
        }

        Integer registerType = platUserVO.getRegisterType();
        String validCode = platUserVO.getCode();
        PlatUser platUser = new PlatUser();
        if (registerType == 1) {
            //手机注册,验证验证码
            platUser.setUsername(platUserVO.getMobile());
            platUser.setMobile(platUserVO.getMobile());
            //验证手机验证码
            smsMessageService.validSmsCode(platUserVO.getMobile(), UserVerifiEnum.USER_REGISTER.getCode(), validCode);
        } else {
            //邮箱注册,验证验证码
            messageSendService.mailValid(UserVerifiEnum.USER_REGISTER.getCode(), VerificationCodeType.REGISTER_CODE, platUserVO.getMail(), validCode);
            platUser.setUsername(platUserVO.getMail());
            platUser.setMail(platUserVO.getMail());
        }
        //解密密码
        String password = RsaUtils.decryptByPrivateKey(platUserVO.getPassword(), RsaUtils.DEFAULT_PRIVATE_KEY);
        platUser.setPassword(password);
        platUser.setInviteCode(platUserVO.getInviteCode());
        platUser.setCountryCode(platUserVO.getCountryCode());
        platUser.setCountryId(platUserVO.getCountryId());
        //platUser.setSource(platUserVO.getSource());
        try {
            platUserService.registerPlatUser(platUser, true);
            // neo4jPlatUserService.save(platUser); // 保存用户节点和关系到NEO4J库
        } catch (PlatException platException) {
            if (platException.getCode() == Constants.INVOTE_CODE_SYNC_ERROR) {
                //邀请码冲突，重试
                platUserService.registerPlatUser(platUser, true);
                // neo4jPlatUserService.save(platUser); // 保存用户节点和关系到NEO4J库
            } else {
                throw platException;
            }
        }
        //清楚验证码
        messageSendService.clearValid(MessageTemplateCode.REGISTER_TEMPLATE.getCode(), VerificationCodeType.REGISTER_CODE.getCode(), platUserVO.getMail());
        return Mono.just(GlobalMessageResponseVo.newSuccessInstance("注册成功"));
    }


    @ValidateGroup(fileds = {
            @ValidateFiled(index = 0, notNull = true, errMsg = "用户名不正确"),
    })
    @RequestMapping("/user/findUser")
    public Mono<GlobalMessageResponseVo> findExistUser(String username) {
        PlatUser platUser = platUserService.findByLoginName(username);
        if (platUser != null) {
            return Mono.just(GlobalMessageResponseVo.newErrorInstance("用户已经注册了"));
        }
        return Mono.just(GlobalMessageResponseVo.newSuccessInstance("用户可以注册"));
    }

    @ValidateGroup(fileds = {
            @ValidateFiled(index = 0, filedName = "mail", regStr = Constants.EMAIL_PATTERN, notNull = true, errMsg = "邮箱不正确"),
            @ValidateFiled(index = 0, filedName = "type", isEnums = true, enums = "login,register,message,reset,withdraw,binder", notNull = true, errMsg = "业务类型不能为空"),
            @ValidateFiled(index = 0, filedName = "code", errMsg = "图形验证码不能为空"),
            @ValidateFiled(index = 0, filedName = "source", notNull = true, errMsg = "客户端来源"),
            @ValidateFiled(index = 0, filedName = "appKey", notNull = true, errMsg = "请升级接口"),
            @ValidateFiled(index = 0, filedName = "sessionId", notNull = true, maxLen = 800, errMsg = "请升级接口"),
            @ValidateFiled(index = 0, filedName = "sig", maxLen = 664, errMsg = "sig,请升级接口"),
            @ValidateFiled(index = 0, filedName = "vtoken", errMsg = "vtoken,请升级接口"),
            @ValidateFiled(index = 0, filedName = "scene", notNull = true, errMsg = "请升级接口")
    })

    //发送邮箱验证码
    @PostMapping("/mail/sendCode")
    public Mono<GlobalMessageResponseVo> sendMessageCode(MessageVO messageVO) {
        /*ServerHttpResponse response = ctx.getResponse();
        HttpHeaders headers = response.getHeaders();
        headers.add("Access-Control-Allow-Origin", "*");
        headers.add("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        headers.add("Access-Control-Max-Age", "3600");
        headers.add("Access-Control-Allow-Headers", "*");
        headers.add("Access-Control-Expose-Headers", "*");
        headers.add("Access-Control-Allow-Credentials", "true");*/

        VerificationCodeType typeEnums = VerificationCodeType.valueToEnums(messageVO.getType());
        Map<String, Object> params = new HashMap<>();
        if (typeEnums == VerificationCodeType.REGISTER_CODE) {
            //邮箱注册邮件
            params.put(MessageSendService.PARAM_CODE, NumberUtils.getRandomNumber(6));
            messageSendService.mailSend(UserVerifiEnum.USER_REGISTER.getCode(), typeEnums, messageVO.getMail(), params);
            return Mono.just(GlobalMessageResponseVo.newSuccessInstance("验证码发送成功"));
        } else if (typeEnums == VerificationCodeType.RESET_CODE) {
            //重置密码邮件
            //String ptoken = UUID.randomUUID().toString().replace("-", "");
            //String ptoken = NumberUtils.getRandomNumber(6);
            //String resetRequest = new StringBuilder(resetUrl).append("?ptoken=").append(ptoken).toString();
            params.put(MessageSendService.PARAM_CODE, NumberUtils.getRandomNumber(6));
            //params.put(MessageSendService.PARAM_CODE, resetRequest);
            messageSendService.mailSend(UserVerifiEnum.USER_FINDPASSWORD.getCode(), typeEnums, messageVO.getMail(), params);
            return Mono.just(GlobalMessageResponseVo.newSuccessInstance("验证码发送成功"));
        } /*else if (typeEnums == VerificationCodeType.WITHDRAW_CODE) {
            params.put(MessageSendService.PARAM_CODE, NumberUtils.getRandomNumber(6));
            messageSendService.mailSend(MessageTemplateCode.WITHDRAW_TEMPLATE.getCode(), typeEnums, messageVO.getMail(), params);
            return Mono.just(GlobalMessageResponseVo.newSuccessInstance("验证码发送成功"));
        } else if (typeEnums == VerificationCodeType.BINDER_CODE) {
            params.put(MessageSendService.PARAM_CODE, NumberUtils.getRandomNumber(6));
            messageSendService.mailSend(MessageTemplateCode.EMAIL_BINDER_TEMPLATE.getCode(), typeEnums, messageVO.getMail(), params);
            return Mono.just(GlobalMessageResponseVo.newSuccessInstance("验证码发送成功"));
        }*/else if (typeEnums == VerificationCodeType.BINDER_CODE) {
            params.put(MessageSendService.PARAM_CODE, NumberUtils.getRandomNumber(6));
            messageSendService.mailSend(UserVerifiEnum.USER_BINDER_EMAIL.getCode(), typeEnums, messageVO.getMail(), params);
            return Mono.just(GlobalMessageResponseVo.newSuccessInstance("验证码发送成功"));
        }
        return Mono.just(GlobalMessageResponseVo.newErrorInstance("不支持的业务类型"));
    }

    @ValidateGroup(fileds = {
            @ValidateFiled(index = 0, filedName = "mobile", notNull = true, errMsg = "手机号不正确"),
            @ValidateFiled(index = 0, filedName = "countryId", errMsg = "手机号区号不正确"),
            @ValidateFiled(index = 0, filedName = "type", isEnums = true, enums = "login,register,message,reset,withdraw,binder_mobile", notNull = true, errMsg = "请输入正确的业务类型"),
            @ValidateFiled(index = 0, filedName = "code", errMsg = "图形验证码不能为空"),
            @ValidateFiled(index = 0, filedName = "source", notNull = true, errMsg = "客户端来源"),
            @ValidateFiled(index = 0, filedName = "appKey", notNull = true, errMsg = "请升级接口"),
            @ValidateFiled(index = 0, filedName = "sessionId", notNull = true, maxLen = 800, errMsg = "请升级接口"),
            @ValidateFiled(index = 0, filedName = "sig", maxLen = 664, errMsg = "sig,请升级接口"),
            @ValidateFiled(index = 0, filedName = "vtoken", errMsg = "vtoken,请升级接口"),
            @ValidateFiled(index = 0, filedName = "scene", notNull = true, errMsg = "请升级接口")
    })

    //发送手机验证码
    @RequestMapping("/mobile/sendCode")
    public Mono<GlobalMessageResponseVo> sendSmsCode(MessageVO messageVO) {
        /*ServerHttpResponse response = ctx.getResponse();
        HttpHeaders headers = response.getHeaders();
        headers.add("Access-Control-Allow-Origin", "*");
        headers.add("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        headers.add("Access-Control-Max-Age", "3600");
        headers.add("Access-Control-Allow-Headers", "*");
        headers.add("Access-Control-Expose-Headers", "*");
        headers.add("Access-Control-Allow-Credentials", "true");*/

        VerificationCodeType typeEnums = VerificationCodeType.valueToEnums(messageVO.getType());
        if (typeEnums == VerificationCodeType.REGISTER_CODE) {
            //手机注册
            //DisruptorData.saveSecurityLog(DisruptorData.buildSecurityLog(messageVO.getCountryId(),messageVO.getMobile(), MessageTemplateCode.MOBILE_REGISTER_TEMPLATE.getCode(), ""));
            smsMessageService.smsSend(messageVO.getMobile(), "true", UserVerifiEnum.USER_REGISTER.getCode());
            return Mono.just(GlobalMessageResponseVo.newSuccessInstance("验证码发送成功"));
        }else if (typeEnums == VerificationCodeType.RESET_CODE) {
            //手机找回密码
            //DisruptorData.saveSecurityLog(DisruptorData.buildSecurityLog(messageVO.getCountryId(),messageVO.getMobile(), MessageTemplateCode.MOBILE_RESET_TEMPLATE.getCode(), ""));
            smsMessageService.smsSend(messageVO.getMobile(), "true", UserVerifiEnum.USER_FINDPASSWORD.getCode());
            return Mono.just(GlobalMessageResponseVo.newSuccessInstance("验证码发送成功"));
        }else if(typeEnums == VerificationCodeType.BINDER_MOBILE_CODE){
            //绑定手机
            smsMessageService.smsSend(messageVO.getMobile(), "true", UserVerifiEnum.USER_BINDER_MOBILE.getCode());
            return Mono.just(GlobalMessageResponseVo.newSuccessInstance("绑定手机验证码发送成功"));
        }
        return Mono.just(GlobalMessageResponseVo.newErrorInstance("不支持的业务类型"));
    }

    @ValidateGroup(fileds = {
            @ValidateFiled(index = 0, filedName = "mobile", notNull = true, errMsg = "请输入正确的手机号")
    })

    @PostMapping("/user/sendMobileSms")
    public Mono<GlobalMessageResponseVo> sendMobileSms(PlatUserVO platUserVO) {
        return ReactiveSecurityContextHolder.getContext()
                .filter(c -> c.getAuthentication() != null)
                .map(SecurityContext::getAuthentication).map(Authentication::getPrincipal).cast(RedisSessionUser.class).flatMap(user -> {
                    DisruptorData.saveSecurityLog(DisruptorData.buildSecurityLog(platUserVO.getCountryId(),platUserVO.getMobile(), MessageTemplateCode.MOBILE_BINDER_TEMPLATE.getCode(), ""));
                    //smsMessageService.sendSms(platUserVO.getMobile(), MessageTemplateCode.MOBILE_BINDER_TEMPLATE.getCode(), "");
                    return Mono.just(GlobalMessageResponseVo.newSuccessInstance("发送短信成功"));
                });
    }

    @ValidateGroup(fileds = {
            @ValidateFiled(index = 0, filedName = "smsType", isEnums = true, enums = "ex_password,bander_google,ex_mobile,exchange_pass,update_password", notNull = true, errMsg = "请输入正确的业务类型")
    })

    //修改交易密码发送验证码
    @PostMapping("/user/mobile/sendMobileSms")
    public Mono<GlobalMessageResponseVo> sendUserMobileSms(PlatUserVO platUserVO) {
        return ReactiveSecurityContextHolder.getContext()
                .filter(c -> c.getAuthentication() != null)
                .map(SecurityContext::getAuthentication).map(Authentication::getPrincipal).cast(RedisSessionUser.class).flatMap(user -> {
                    /*if (StringUtils.isBlank(user.getMobile())) {
                        return Mono.just(GlobalMessageResponseVo.newErrorInstance("请先绑定手机号"));
                    }*/
                    VerificationCodeType typeEnums = VerificationCodeType.valueToEnums(platUserVO.getSmsType());
                    if (typeEnums == VerificationCodeType.EX_TRADE_PASS) {
                        //设置交易密码
                        //验证手机号不为空则发送手机验证码
                        if(!StringUtils.isBlank(user.getMobile())){
                            smsMessageService.smsSend(user.getMobile(), "true", UserVerifiEnum.USER_EX_PASSWORD.getCode());
                            return Mono.just(GlobalMessageResponseVo.newSuccessInstance("验证码发送成功"));
                        //验证邮箱不为空则发送邮箱验证码
                        }else if(!StringUtils.isBlank(user.getMail())){
                            Map<String, Object> params = new HashMap<>();
                            params.put(MessageSendService.PARAM_CODE, NumberUtils.getRandomNumber(6));
                            messageSendService.mailSend(UserVerifiEnum.USER_EX_PASSWORD.getCode(), typeEnums, user.getMail(), params);
                            return Mono.just(GlobalMessageResponseVo.newSuccessInstance("验证码发送成功"));
                        }else{
                            return Mono.just(GlobalMessageResponseVo.newErrorInstance("验证码发送失败"));
                        }
                    }else if(typeEnums == VerificationCodeType.EX_TRADE_MOBILE){
                        //交易验证
                        //验证手机号不为空则发送手机验证码
                        if(!StringUtils.isBlank(user.getMobile())){
                            smsMessageService.smsSend(user.getMobile(), "true", UserVerifiEnum.USER_EX_MOBILE.getCode());
                            return Mono.just(GlobalMessageResponseVo.newSuccessInstance("验证码发送成功"));
                        //验证邮箱不为空则发送邮箱验证码
                        }else if(!StringUtils.isBlank(user.getMail())){
                            Map<String, Object> params = new HashMap<>();
                            params.put(MessageSendService.PARAM_CODE, NumberUtils.getRandomNumber(6));
                            messageSendService.mailSend(UserVerifiEnum.USER_EX_MOBILE.getCode(), typeEnums, user.getMail(), params);
                            return Mono.just(GlobalMessageResponseVo.newSuccessInstance("验证码发送成功"));
                        }else{
                            return Mono.just(GlobalMessageResponseVo.newErrorInstance("验证码发送失败"));
                        }
                    }else if(typeEnums == VerificationCodeType.UPDATE_PASSWORD){
                        //修改登录密码
                        //验证手机号不为空则发送手机验证码
                        if(!StringUtils.isBlank(user.getMobile())){
                            smsMessageService.smsSend(user.getMobile(), "true", UserVerifiEnum.USER_UPDATEPASSWORD.getCode());
                            return Mono.just(GlobalMessageResponseVo.newSuccessInstance("修改登录密码验证码发送成功"));
                        //验证邮箱不为空则发送邮箱验证码
                        }else if(!StringUtils.isBlank(user.getMail())){
                            Map<String, Object> params = new HashMap<>();
                            params.put(MessageSendService.PARAM_CODE, NumberUtils.getRandomNumber(6));
                            messageSendService.mailSend(UserVerifiEnum.USER_UPDATEPASSWORD.getCode(), typeEnums, user.getMail(), params);
                            return Mono.just(GlobalMessageResponseVo.newSuccessInstance("修改登录密码验证码发送成功"));
                        }else{
                            return Mono.just(GlobalMessageResponseVo.newErrorInstance("验证码发送失败"));
                        }
                    }
                    return Mono.just(GlobalMessageResponseVo.newErrorInstance("不支持的业务类型"));
                });
    }

    @ValidateGroup(fileds = {
            @ValidateFiled(index = 0, filedName = "smsType", isEnums = true, enums = "ex_password_mail,ex_mail,exchange_pass,bander_google_mail", notNull = true, errMsg = "请输入正确的业务类型")
    })
    @PostMapping("/user/mail/sendMail")
    public Mono<GlobalMessageResponseVo> sendUserMail(PlatUserVO platUserVO) {
        return ReactiveSecurityContextHolder.getContext()
                .filter(c -> c.getAuthentication() != null)
                .map(SecurityContext::getAuthentication).map(Authentication::getPrincipal).cast(RedisSessionUser.class).flatMap(user -> {
                    if (StringUtils.isBlank(user.getMail())) {
                        return Mono.just(GlobalMessageResponseVo.newErrorInstance("请先绑定邮箱"));
                    }
                    VerificationCodeType typeEnums = VerificationCodeType.valueToEnums(platUserVO.getSmsType());
                    Map<String, Object> params = new HashMap<>();
                    /*if (typeEnums == VerificationCodeType.EX_TRADE_MAIL) {
                        params.put(MessageSendService.PARAM_CODE, NumberUtils.getRandomNumber(6));
                        messageSendService.mailSend(MessageTemplateCode.EMAIL_EX_TRADE_TEMPLATE.getCode(), typeEnums, user.getMail(), params);
                        return Mono.just(GlobalMessageResponseVo.newSuccessInstance("验证码发送成功"));
                    }
                    if (typeEnums == VerificationCodeType.EX_EXCHANGE_PASS) {
                        params.put(MessageSendService.PARAM_CODE, NumberUtils.getRandomNumber(6));
                        messageSendService.mailSend(MessageTemplateCode.EMAIL_EXCHANGE_PASS_TEMPLATE.getCode(), typeEnums, user.getMail(), params);
                        return Mono.just(GlobalMessageResponseVo.newSuccessInstance("验证码发送成功"));
                    }
                    if (typeEnums == VerificationCodeType.EX_PASS_MAIL) {
                        params.put(MessageSendService.PARAM_CODE, NumberUtils.getRandomNumber(6));
                        messageSendService.mailSend(MessageTemplateCode.EMAIL_TRADE_PASSWORD_TEMPLATE.getCode(), typeEnums, user.getMail(), params);
                        return Mono.just(GlobalMessageResponseVo.newSuccessInstance("验证码发送成功"));
                    }
                    if(typeEnums == VerificationCodeType.BINDER_GOOGLE_CODE_MAIL) {
                    	params.put(MessageSendService.PARAM_CODE, NumberUtils.getRandomNumber(6));
                        messageSendService.mailSend(MessageTemplateCode.EMAIL_BINDER_GOOGLE_TEMPLATE.getCode(), typeEnums, user.getMail(), params);
                        return Mono.just(GlobalMessageResponseVo.newSuccessInstance("验证码发送成功"));
                    }*/
                    return Mono.just(GlobalMessageResponseVo.newErrorInstance("不支持的业务类型"));
                });
    }

    /**
     * 修改手机号
     *
     * @param platUserVO
     * @return
     */
    @ValidateGroup(fileds = {
            @ValidateFiled(index = 0, filedName = "mobile",errMsg = "请输入正确的手机号"),
    })
    @PostMapping("/user/updateMobileSms")
    public Mono<GlobalMessageResponseVo> sendUpdateMobileSms(PlatUserVO platUserVO) {
        return ReactiveSecurityContextHolder.getContext()
                .filter(c -> c.getAuthentication() != null)
                .map(SecurityContext::getAuthentication).map(Authentication::getPrincipal).cast(RedisSessionUser.class).flatMap(user -> {
                    String mobile = platUserVO.getMobile();
                    if (StringUtils.isBlank(mobile)) {
                        mobile = user.getMobile();
                    }
                    String countryId = platUserVO.getCountryId() ;
                    if(StringUtils.isBlank(countryId)) {
                        countryId = user.getCountryId() ;
                    }
                    //smsMessageService.sendSms(mobile, MessageTemplateCode.MOBILE_BINDER_UPDATE.getCode(), "");
                    DisruptorData.saveSecurityLog(DisruptorData.buildSecurityLog(countryId,mobile, MessageTemplateCode.MOBILE_BINDER_UPDATE.getCode(), ""));
                    return Mono.just(GlobalMessageResponseVo.newSuccessInstance("发送短信成功"));
                });
    }

    @ValidateGroup(fileds = {
            @ValidateFiled(index = 0, filedName = "mobile", notNull = true, errMsg = "请输入正确的手机号"),
            @ValidateFiled(index = 0, regStr = "\\d{4,6}", filedName = "code", notNull = true, errMsg = "请输入正确的手机号验证码")
    })

    //绑定手机
    @PostMapping("/user/mobileBinder")
    public Mono<GlobalMessageResponseVo> binderMobile(SmsMessageVO messageVO) {
        return ReactiveSecurityContextHolder.getContext()
                .filter(c -> c.getAuthentication() != null)
                .map(SecurityContext::getAuthentication).map(Authentication::getPrincipal).cast(RedisSessionUser.class).flatMap(user -> {
                    if (smsMessageService.validSmsCode(messageVO.getMobile(), UserVerifiEnum.USER_BINDER_MOBILE.getCode(), messageVO.getCode())) {
                        PlatUser exist = platUserService.findByLoginName(messageVO.getMobile());
                        if (exist != null) {
                            return Mono.just(GlobalMessageResponseVo.newErrorInstance("该手机号已经绑定了"));
                        }
                        PlatUser platUser = new PlatUser();
                        platUser.setMobile(messageVO.getMobile());
                        platUser.setId(user.getId());
                        platUser.setCountryId(messageVO.getCountryId());
                        //platUser.setMobileAuditDate(LocalDateTime.now()); //手机认证时间
                        platUserService.updateById(platUser);

                        //更新redis数据
                        user.setMobile(messageVO.getMobile());
                        user.setCountryId(messageVO.getCountryId());
                        stringRedisTemplate.opsForHash().put(SercurityConstant.SESSION_TOKEN_REDIS_NAMESAPCE + user.getToken(), SercurityConstant.SESSION_TOKEN_REDIS_USER, JsonUtils.toJson(user));
                        //异步解析用户归属地
                        /*DisruptorManager.instance().runConfig();
                        DisruptorData data = new DisruptorData();
                        data.setType(3);
                        platUser.setReferId(user.getReferId());
                        data.setPlatUser(platUser);
                        DisruptorManager.instance().publishData(data);*/
                        return Mono.just(GlobalMessageResponseVo.newSuccessInstance("绑定手机号成功"));
                    }
                    return Mono.just(GlobalMessageResponseVo.newErrorInstance("绑定手机号失败"));
                });
    }

    @ValidateGroup(fileds = {
            @ValidateFiled(index = 0, filedName = "mail", regStr = Constants.EMAIL_PATTERN, notNull = true, errMsg = "请输入正确的邮箱"),
            @ValidateFiled(index = 0, regStr = "\\d{4,6}", filedName = "code", notNull = true, errMsg = "请输入正确的邮箱验证码")
    })

    //绑定邮箱
    @PostMapping("/user/binderEmail")
    public Mono<GlobalMessageResponseVo> binderEmail(SmsMessageVO messageVO) {
        return ReactiveSecurityContextHolder.getContext()
                .filter(c -> c.getAuthentication() != null)
                .map(SecurityContext::getAuthentication).map(Authentication::getPrincipal).cast(RedisSessionUser.class).flatMap(user -> {
                    messageSendService.mailValid(UserVerifiEnum.USER_BINDER_EMAIL.getCode(), VerificationCodeType.BINDER_CODE, messageVO.getMail(), messageVO.getCode());
                    PlatUser exist = platUserService.findByLoginName(messageVO.getMail());
                    if (exist != null) {
                        return Mono.just(GlobalMessageResponseVo.newErrorInstance("该邮箱已经绑定了"));
                    }
                    PlatUser platUser = new PlatUser();
                    platUser.setMail(messageVO.getMail());
                    platUser.setId(user.getId());
                    platUserService.updateById(platUser);
                    //更新redis数据
                    user.setMail(messageVO.getMail());
                    stringRedisTemplate.opsForHash().put(SercurityConstant.SESSION_TOKEN_REDIS_NAMESAPCE + user.getToken(), SercurityConstant.SESSION_TOKEN_REDIS_USER, JsonUtils.toJson(user));
                    return Mono.just(GlobalMessageResponseVo.newSuccessInstance("绑定邮箱成功"));
                });
    }


    @ValidateGroup(fileds = {
            @ValidateFiled(index = 0, filedName = "password", notNull = true, errMsg = "请输入格式正确的密码"),
            @ValidateFiled(index = 0, filedName = "oldPassword", notNull = true, errMsg = "请输入格式正确的原始密码"),
    })

    //修改登录密码
    @PostMapping("/user/updatePassword")
    public Mono<GlobalMessageResponseVo> findPassword(PlatUserVO platUserVO) {
        return ReactiveSecurityContextHolder.getContext()
                .filter(c -> c.getAuthentication() != null)
                .map(SecurityContext::getAuthentication).map(Authentication::getPrincipal).cast(RedisSessionUser.class).flatMap(user -> this.updatePassword(user, platUserVO));
    }

    private Mono<GlobalMessageResponseVo> updatePassword(RedisSessionUser user, PlatUserVO platUserVO) {
        PlatUser platUser = new PlatUser();
        platUser.setId(user.getId());
        String decryPassword = RsaUtils.decryptByPrivateKey(platUserVO.getPassword(), RsaUtils.DEFAULT_PRIVATE_KEY);
        String decryOldPassword = RsaUtils.decryptByPrivateKey(platUserVO.getOldPassword(), RsaUtils.DEFAULT_PRIVATE_KEY);
        platUser.setPassword(decryPassword);
        platUser.setOldPassword(decryOldPassword);
        //验证验证码
        //手机号码不为空则验证手机验证码
        if(!StringUtils.isBlank(user.getMobile())){
            smsMessageService.validSmsCode(user.getMobile(), UserVerifiEnum.USER_UPDATEPASSWORD.getCode(), platUserVO.getSmsCode());
        //邮箱不为空则验证邮箱验证码
        }else if(!StringUtils.isBlank(user.getMail())){
            messageSendService.mailValid(UserVerifiEnum.USER_UPDATEPASSWORD.getCode(), VerificationCodeType.UPDATE_PASSWORD, user.getMail(), platUserVO.getSmsCode());
        }else{
            return Mono.just(GlobalMessageResponseVo.newSuccessInstance("验证码验证失败"));
        }
        /*boolean b = smsMessageService.validSmsCode(user.getMobile(), UserVerifiEnum.USER_UPDATEPASSWORD.getCode(), platUserVO.getSmsCode());
        if(b == false){
            return Mono.just(GlobalMessageResponseVo.newSuccessInstance("验证码验证失败"));
        }*/
        try {
            platUserService.updatePassword(platUser);
        } catch (Exception e) {
            throw e;
        }
        return Mono.just(GlobalMessageResponseVo.newSuccessInstance("更新密码成功"));
    }

    @ValidateGroup(fileds = {
            @ValidateFiled(index = 0, filedName = "mail", notNull = true, errMsg = "请输入格式正确的邮箱"),
            @ValidateFiled(index = 0, filedName = "password", notNull = true, errMsg = "请输入格式正确的密码"),
            @ValidateFiled(index = 0, filedName = "repassword", notNull = true, errMsg = "请输入格式正确的重复密码"),
            @ValidateFiled(index = 0, filedName = "code", notNull = true, errMsg = "重置密码验证码不能为空"),
    })

    //邮箱找回密码
    @PostMapping("/user/mail/resetpwd")
    public Mono<GlobalMessageResponseVo> resetPassword(PlatUserVO platUserVO) {
        PlatUser platUser = new PlatUser();
        String decryPassword = RsaUtils.decryptByPrivateKey(platUserVO.getPassword(), RsaUtils.DEFAULT_PRIVATE_KEY);
        platUser.setPassword(decryPassword);
        platUser.setPtoken(platUserVO.getCode());
        platUser.setMail(platUserVO.getMail());
        platUserService.resetPassword(platUser);
        return Mono.just(GlobalMessageResponseVo.newSuccessInstance("重置密码成功"));
    }

    @ValidateGroup(fileds = {
            @ValidateFiled(index = 0, filedName = "mobile", notNull = true, errMsg = "请输入格式正确的手机"),
            @ValidateFiled(index = 0, filedName = "password", notNull = true, errMsg = "请输入格式正确的密码"),
            @ValidateFiled(index = 0, filedName = "repassword", notNull = true, errMsg = "请输入格式正确的重复密码"),
            @ValidateFiled(index = 0, filedName = "countryId", errMsg = "请输入格式正确的区号"),
            @ValidateFiled(index = 0, filedName = "code", regStr = "\\d{4,6}", notNull = true, errMsg = "请输入正确的手机验证码"),
    })

    //手机找回密码
    @PostMapping("/user/mobile/resetpwd")
    public Mono<GlobalMessageResponseVo> resetMobilePassword(PlatUserVO platUserVO) {
        //验证验证码
        if (smsMessageService.validSmsCode(platUserVO.getMobile(), UserVerifiEnum.USER_FINDPASSWORD.getCode(),platUserVO.getCode())) {
            //验证短信验证码
            if(!platUserVO.getPassword().equals(platUserVO.getRepassword())){
                return Mono.just(GlobalMessageResponseVo.newErrorInstance("重复密码不一致"));
            }
            PlatUser platUser = new PlatUser();
            String decryPassword = RsaUtils.decryptByPrivateKey(platUserVO.getPassword(), RsaUtils.DEFAULT_PRIVATE_KEY);
            platUser.setPassword(decryPassword);
            platUser.setMobile(platUserVO.getMobile());
            try {
                platUserService.resetPasswordByMobile(platUser);
            } catch (Exception e) {
                throw e;
            }
            return Mono.just(GlobalMessageResponseVo.newSuccessInstance("重置密码成功"));
        }
        return Mono.just(GlobalMessageResponseVo.newErrorInstance("重置密码失败"));
    }

    @ValidateGroup(fileds = {
            @ValidateFiled(index = 0, filedName = "exPassword", notNull = true, errMsg = "请输入格式正确的交易密码"),
            @ValidateFiled(index = 0, filedName = "code", notNull = true, errMsg = "请输入格式正确的短信验证码")
    })

    //修改交易密码
    @PostMapping("/user/updateExPassword")
    public Mono<GlobalMessageResponseVo> updateExPassword(PlatUserVO platUserVO) {
        return ReactiveSecurityContextHolder.getContext()
                .filter(c -> c.getAuthentication() != null)
                .map(SecurityContext::getAuthentication).map(Authentication::getPrincipal).cast(RedisSessionUser.class).flatMap(user -> this.updateExPassword(user, platUserVO));
    }

    private Mono<GlobalMessageResponseVo> updateExPassword(RedisSessionUser user, PlatUserVO platUserVO) {

        String exDecryPassword = RsaUtils.decryptByPrivateKey(platUserVO.getExPassword(), RsaUtils.DEFAULT_PRIVATE_KEY);
        String decodeExPassword = passwordEncoder.encode(exDecryPassword);
        //验证验证码
        //手机号码不为空则验证手机验证码
        if(!StringUtils.isBlank(user.getMobile())){
            smsMessageService.validSmsCode(user.getMobile(), UserVerifiEnum.USER_EX_PASSWORD.getCode(), platUserVO.getCode());
        //邮箱不为空则验证邮箱验证码
        }else if(!StringUtils.isBlank(user.getMail())){
            messageSendService.mailValid(UserVerifiEnum.USER_EX_PASSWORD.getCode(), VerificationCodeType.EX_TRADE_PASS, user.getMail(), platUserVO.getCode());
        }else{
            return Mono.just(GlobalMessageResponseVo.newSuccessInstance("验证码验证失败"));
        }
        PlatUser platUser = new PlatUser();
        platUser.setExPassword(decodeExPassword);
        platUser.setId(user.getId());
        try {
            platUserService.updateExpasswordById(platUser);
        } catch (Exception e) {
            throw e;
        }
        //刷选设置用户的交易密码
        user.setExPassword(decodeExPassword);
        //更新redis数据
        stringRedisTemplate.opsForHash().put(SercurityConstant.SESSION_TOKEN_REDIS_NAMESAPCE + user.getToken(), SercurityConstant.SESSION_TOKEN_REDIS_USER, JsonUtils.toJson(user));
        return Mono.just(GlobalMessageResponseVo.newSuccessInstance("设置交易密码成功"));
    }


}
